﻿#region << 文 件 说 明 >>

/*----------------------------------------------------------------
// 文件名称：OpenApiResultProvider
// 创 建 者：billsking
// 创建时间：2024年12月26日 星期四 11:13
// 文件版本：V1.0.0
----------------------------------------------------------------*/

#endregion

using System.Runtime.CompilerServices;
using Furion;
using Furion.DataValidation;
using Furion.FriendlyException;
using Furion.JsonSerialization;
using Furion.UnifyResult;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace WebApp;

/// <summary>
/// 
/// </summary>
[UnifyModel(typeof(OpenApiResult<>))]
public class OpenApiResultProvider: IUnifyResultProvider
{
    public IActionResult OnAuthorizeException(DefaultHttpContext context, ExceptionMetadata metadata)
    {
        return new JsonResult( RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)
            , UnifyContext.GetSerializerSettings(context));
    }

    public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
    {
        return new JsonResult( RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)
            , UnifyContext.GetSerializerSettings(context));
    }

    public IActionResult OnSucceeded(ActionExecutedContext context, object data)
    {
        //判断data是否为元组类型
        if (data is ITuple)
        {
            ITuple tuple =(ITuple)data;
            var error = tuple[1];
            var resultData = tuple.Length == 3 ? tuple[2] : null;
            return new JsonResult( RESTfulResult((int)tuple[0]!, resultData, error)
                , UnifyContext.GetSerializerSettings(context));
        }
        return new JsonResult( RESTfulResult(StatusCodes.Status200OK, data)
            , UnifyContext.GetSerializerSettings(context));
    }
    public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
    {
        return new JsonResult( RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.FirstErrorMessage)
            , UnifyContext.GetSerializerSettings(context));
    }

    public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
    {
        // 设置响应状态码
        UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings);

        switch (statusCode)
        {
            // 处理 401 状态码
            case StatusCodes.Status401Unauthorized:
                var msg = "401 登录已过期，请重新登录";
                await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: msg),
                    App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                break;
            // 处理 403 状态码
            case StatusCodes.Status403Forbidden:
                await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 禁止访问，没有权限"),
                    App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                break;
            // 处理 302 状态码
            case StatusCodes.Status302Found:
                if (context.Response.Headers.TryGetValue("Location", out var redirectUrl))
                {
                    context.Response.Redirect(redirectUrl!);
                }
                else
                {
                    var errorMessage = "302 跳转失败，没有提供 Location 头信息";
                    await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: errorMessage),
                        App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                }
                break;
        }
    }
    
    private static OpenApiResult<object> RESTfulResult(int statusCode, object? data = default, object? errors = default)
    {
        return new OpenApiResult<object>(){
            Code = statusCode == StatusCodes.Status200OK ? 0 : statusCode,
            Data = data,
            Message = errors is null or string ? (errors + "") : JSON.Serialize(errors),
            Extras = UnifyContext.Take(),
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()};
    }
}